// Copyright 2011 and onwards Noam Shazeer and Georges Harik

#include "intsequences.h"
#include <strstream>

bool LoadSequence(istream &in, Sequence & s) {
  s.v_.clear();
  char c;
  if (!(in >> c)) return false;
  CHECK(c == 'A');
  in >> s.id_;
  bool ok = true;
  in >> c;
  CHECK(c == ',');
  while (in.peek() != '\n') {
    string tok;
    while (in.peek() != ',') tok += in.get();
    istringstream istr(tok);
    int64 i;
    istr >> i;
    ostringstream ostr;
    ostr << i;
    if (ostr.str() != tok) ok = false;
    if (abs(i) >= (1LL << 60)) ok = false;
    if (ok) s.v_.push_back(i);
    CHECK(in.get() == ',');
  }
  in >> ws;
  return true;
}

bool operator <(const Sequence &a, const Sequence &b) {
  uint32 shared_length = min(a.v_.size(), b.v_.size());
  for (uint32 i=0; i<shared_length; i++) {
    if (a.v_[i] < b.v_[i]) return true;
    if (b.v_[i] < a.v_[i]) return false;
  }
  if (a.v_.size() < b.v_.size()) return true;
  return false;
}

/*
bool operator ==(const Sequence &a, const Sequence &b) {
  if (b.v_.size() != a.v_.size()) return false;
  for (uint32 i=0; i < a.v_.size(); i++) {  
    if (a.v_[i] != b.v_[i]) return false;
  }
  return true;
  }*/

void SequenceIndex::Load() {
  cout << "Loading sequences " << endl;
  ifstream input("sequences.bin", ios::in | ios::binary);
  input.read((char *)&num_sequences_, sizeof(int32));
  lengths_ = new int32[num_sequences_];
  ranks_ = new int32[num_sequences_];
  rank_id_ = new int32[num_sequences_];
  descriptions_ = new char *[num_sequences_];
  sequences_ = new int64 *[num_sequences_];
  input.read((char *)lengths_, num_sequences_ * sizeof(int32));
  input.read((char *)ranks_, num_sequences_ * sizeof(int32));
  input.read((char *)rank_id_, num_sequences_ * sizeof(int32));
  for (int i=0; i<num_sequences_; i++) {
    int32 desc_size;
    input.read((char *)&desc_size, sizeof(int32));
    descriptions_[i] = new char[desc_size];
    input.read(descriptions_[i], desc_size);
  }
  for (int i=0; i<num_sequences_; i++) {
    sequences_[i] = new int64[lengths_[i]];
    input.read((char *)(sequences_[i]), lengths_[i] * sizeof(int64));
  }
  if (G_CONFIG->Exists("max-sequences")) {
    num_sequences_ = ConfigInt("max-sequences");
  }		 
}

void MakeBinarySequenceFile() {

  // Read the integers
  ifstream input("stripped");
  vector<Sequence> seqs;
  Sequence s;
  while (LoadSequence(input, s)) {
    while (s.id_ >= seqs.size()) 
      seqs.push_back(Sequence::MakeSequence(seqs.size()));
    seqs[s.id_] = s;
  }

  // Sort them lexicographically
  vector<Sequence> sorted_seqs = seqs;
  sort(sorted_seqs.begin(), sorted_seqs.end());

  // Read the descriptions
  ifstream desc("names");
  char buf[1001];
  char c;
  while (desc >> c) {
    CHECK(c == 'A');
    uint32 id; 
    desc >> id; desc.get(); desc.getline(buf, 1001);
    if (id < seqs.size()) seqs[id].description_ = buf;
  }

  ofstream out("sequences.bin", ios::out | ios::binary);
  int32 num_sequences = seqs.size();
  out.write((char *)&num_sequences, sizeof(int32));
  for (int i=0; i<num_sequences; i++) {
    int32 length = seqs[i].v_.size();
    out.write((char *) &length, sizeof(int32));
  }
  
  vector<int32> id_rank(num_sequences);
  for (int i=0; i<num_sequences; i++) id_rank[sorted_seqs[i].id_] = i;
  out.write((char *)(&(id_rank[0])), sizeof(int32) * num_sequences);

  for (int i=0; i<num_sequences; i++) {
    int32 rank_id = sorted_seqs[i].id_;
    out.write((char *) &rank_id, sizeof(int32));
  }
  for (int i=0; i<num_sequences; i++) {
    string description = seqs[i].description_;
    int32 desc_size = description.size() + 1;
    out.write((char *)&desc_size, sizeof(int32));
    out.write(description.c_str(), desc_size);
  }
  for (int i=0; i<num_sequences; i++) {
    int32 seq_size = seqs[i].v_.size();
    out.write((char *)&(seqs[i].v_[0]), seq_size * sizeof(int64));
  }
}

void IntegerMakeExplicitProblemFile() {
  ifstream input("stripped");
  ofstream output("integer_explicit_problem");
  Sequence s;
  while (LoadSequence(input, s)) {
    for (uint64 i=0; i<s.v_.size(); i++) 
      output << "(" << s.id_ << " " << i << " " << s.v_[i] << ")\n";    
  }
  ifstream desc("names");
  char buf[1001];
  char c;
  while (desc >> c) {
    CHECK(c == 'A');
    int id;
    desc >> id;
    desc.get();
    desc.getline(buf, 1001);
    string s = buf;
    for (uint64 i=0; i<s.size(); i++) if (s[i] == '"') s[i] = ' ';
    output << "(comment " << id << " \"" << s << "\")\n";
  }
}



